<

ヒーローアニメーション

ヒーローアニメを何度も見たことがあるでしょう。たとえば、画面に次のように表示されます。 販売商品を表すサムネイルのリスト。項目を選択すると、次の場所に移動します 新しい画面には、詳細と「購入」ボタンが表示されます。からの画像を飛ばす ある画面から別の画面への接続は、ヒーローアニメーションFlutter でも同じですが、 モーションは時々、共有要素の遷移

ヒーロー ウィジェットを紹介するこの 1 分間のビデオをご覧ください。

このガイドでは、標準的なヒーロー アニメーションとヒーローの作成方法を説明します。 画像を円形から四角形に変換するアニメーション 飛行中。

このアニメーションは、Hero ウィジェットを使用して Flutter で作成できます。 主人公が出発地から目的地までのルートをアニメーション化すると、 目的地のルート (主人公を除く) が視界に消えます。 通常、ヒーローは画像などの UI の小さな部分です。 両方のルートに共通すること。ユーザーの視点から 主人公はルート間を「飛行」します。このガイドではその方法を示します 次のヒーロー アニメーションを作成します。

標準的なヒーローアニメーション

標準的なヒーローアニメーション主人公をあるルートから新しいルートに飛ばし、 通常、異なる場所に異なるサイズで着陸します。

次のビデオ (低速で録画) は典型的な例を示しています。 ルートの中央にあるフリッパーをタップすると、ルートに飛びます。 新しい青いルートの左上隅を小さいサイズで表示します。 青いルートでフリッパーをタップする(またはデバイスの 前のルートに戻るジェスチャ) フリッパーを元のルートに戻します 本来のルート。


ラジアルヒーローアニメーション

放射状のヒーローアニメーション、主人公がルート間を飛ぶとき 形状が円形から長方形に変化して見える。

以下の動画(低速で録画)、 に、放射状のヒーロー アニメーションの例を示します。初めに、 ルートの下部に 3 つの円形の画像の列が表示されます。 円形の画像のいずれかをタップすると、その画像が新しいルートに移動します 四角形で表示されます。 正方形の画像をタップすると、主人公は次の場所に戻ります。 元のルートが円形で表示されます。


固有のセクションに進む前に標準また放射状のヒーローアニメーション、 読むヒーローアニメーションの基本構造ヒーローアニメーションのコードを構造化する方法を学ぶため、 と舞台裏で理解する Flutter がヒーロー アニメーションを実行する方法。

ヒーローアニメーションの基本構造

ヒーロー アニメーションは 2 つを使用して実装されますHeroウィジェット: ソースルート内のウィジェットを説明するウィジェット、 もう 1 つは、宛先ルート内のウィジェットを説明するものです。 ユーザーの視点からは、主人公は共有されているように見えますが、 この実装の詳細を理解する必要があるのはプログラマのみです。 ヒーロー アニメーション コードは次の構造になっています。

  1. 開始ヒーロー ウィジェットを定義します。ソース ヒーロー。主人公はそのグラフィック表現を指定します (通常は画像)、識別タグが含まれており、 ソースルートによって定義された、現在表示されているウィジェットツリー。
  2. エンディング ヒーロー ウィジェットを定義します。目的地のヒーロー。 このヒーローはグラフィック表現も指定しており、 ソースヒーローと同じタグ。 これは両方のヒーロー ウィジェットを作成するために不可欠です 同じタグ、通常は、を表すオブジェクトです。 基礎となるデータ。最良の結果を得るために、ヒーローは次のことを行う必要があります 実質的に同一のウィジェット ツリー。
  3. 目的地のヒーローを含むルートを作成します。 宛先ルートは、存在するウィジェット ツリーを定義します。 アニメーションの最後に。
  4. 目的地のルートをプッシュしてアニメーションをトリガーします。 ナビゲーターのスタック。 Navigator のプッシュおよびポップ操作のトリガー 一致するタグを持つヒーローの各ペアのヒーロー アニメーション 送信元ルートと宛先ルート。

Flutter は、ヒーローの境界をアニメーション化するトゥイーンを計算します。 始点から終点まで(サイズと位置を補間)、 オーバーレイでアニメーションを実行します。

次のセクションでは、Flutter のプロセスについて詳しく説明します。

舞台裏

以下では、Flutter がどのように実行するかを説明します。 あるルートから別のルートへの移行。

Before the transition the source hero appears in the source route

移行前に、ソースヒーローはソースで待機します ルートのウィジェットツリー。宛先ルートはまだ存在しません。 オーバーレイは空です。


The transition begins

へのルートをプッシュするNavigatorアニメーションをトリガーします。 t=0.0 で、Flutter は次のことを行います。

  • 目的地のヒーローのパスを画面外で計算します。 資料で説明されているように、曲線モーションを使用します。 モーションスペック。 flutterはヒーローがどこに行き着くのかを知っています。

  • 目的のヒーローをオーバーレイに配置します。 と同じ位置とサイズで、ソースヒーロー。 ヒーローをオーバーレイに追加すると、その Z オーダーが変更されます。 すべてのルートの先頭に表示されます。

  • ソースヒーローを画面外に移動します。


The hero flies in the overlay to its final position and size

ヒーローが飛行すると、その長方形の境界が次の方法でアニメーション化されます。トゥイーン<Rect>、ヒーローズで指定されていますcreateRectTween財産。 デフォルトでは、Flutter は次のインスタンスを使用します。MaterialRectArcTweenをアニメーション化します。 曲線のパスに沿った長方形の対角。 (見るラジアルヒーローアニメーションたとえば 別のトゥイーン アニメーションを使用します)。


When the transition is complete, the hero is moved from the overlay to the destination route

フライトが完了すると:

  • Flutter はヒーロー ウィジェットをオーバーレイから次の場所に移動します。 目的地のルート。オーバーレイは空になりました。

  • 目的地のヒーローが最終位置に表示されます 目的地のルートで。

  • ソースヒーローがルートに復元されます。


ルートをポップすると同じプロセスが実行されます。 ヒーローをアニメートして元のサイズに戻す およびソースルート内の場所。

必須クラス

このガイドの例では、次のクラスを使用して、 ヒーローアニメーションを実装します。

Hero
送信元から宛先のルートに移動するウィジェット。 ソース ルートに 1 つのヒーローを定義し、ソース ルートに別のヒーローを定義します。 宛先ルートを指定し、それぞれに同じタグを割り当てます。 Flutter は、一致するタグを持つヒーローのペアをアニメーション化します。
Inkwell
ヒーローをタップしたときに何が起こるかを指定します。 のInkWellonTap()メソッドは 新しいルートをプッシュして、Navigatorのスタック。
Navigator
Navigatorルートのスタックを管理します。ルートをプッシュするか、 からルートをポップするNavigatorのスタックがアニメーションをトリガーします。
Route
画面またはページを指定します。ほとんどのアプリは、 最も基本的なものを超えて、複数のルートがあります。

標準的なヒーローアニメーション

どうしたの?

あるルートから別のルートへの画像のフライングは簡単に実装できます Flutterのヒーローウィジェットを使用します。使用するときc20f9cf3-47ad-4e33-812a-c8e2856b779​​e新しいルートを指定するには、画像が曲線のパスに沿って飛行し、 によって説明されているように、マテリアルデザインのモーションスペック。

新しい Flutter サンプルを作成すると からのファイルを使用して更新します。ヒーローアニメーション。

例を実行するには:

  • ホームルートの写真をタップすると、画像が新しいルートに移動します 同じ写真を異なる場所と縮尺で表示します。
  • 画像をタップするか、 を使用して前のルートに戻ります。 デバイスの前のルートに戻るジェスチャ。
  • を使用すると、移行をさらに遅くすることができます。timeDilation財産。

PhotoHeroクラス

カスタム PhotoHero クラスはヒーローを維持します。 サイズ、画像、タップ時の動作など。 PhotoHero は次のウィジェット ツリーを構築します。

PhotoHero class widget tree

コードは次のとおりです。

class PhotoHero extends StatelessWidget {
  const PhotoHero({ Key key, this.photo, this.onTap, this.width }) : super(key: key);

  final String photo;
  final VoidCallback onTap;
  final double width;

  Widget build(BuildContext context) {
    return SizedBox(
      width: width,
      child: Hero(
        tag: photo,
        child: Material(
          color: Colors.transparent,
          child: InkWell(
            onTap: onTap,
            child: Image.asset(
              photo,
              fit: BoxFit.contain,
            ),
          ),
        ),
      ),
    );
  }
}

重要な情報:

  • 開始ルートは暗黙的にプッシュされます。MaterialAppいつHeroAnimationアプリのホーム プロパティとして提供されます。
  • アンInkWell画像をラップするので、タップを追加するのが簡単になります ソースと宛先のヒーローの両方にジェスチャーをします。
  • 透明色を使用したマテリアル ウィジェットの定義 画像を背景から「飛び出す」ことができます。 目的地に向かって飛びます。
  • SizedBox開始時のヒーローのサイズを指定し、 アニメーションの終わり。
  • 画像の設定fit財産をBoxFit.contain、 実行中に画像が可能な限り大きくなるようにします。 アスペクト比を変更せずに遷移します。

HeroAnimation クラス

HeroAnimationクラスはソースと宛先を作成します PhotoHeroes を選択し、トランジションを設定します。

コードは次のとおりです。

class HeroAnimation extends StatelessWidget {
  Widget build(BuildContext context) {
    timeDilation = 5.0; // 1.0 means normal animation speed.

    return Scaffold(
      appBar: AppBar(
        title: const Text('Basic Hero Animation'),
      ),
      body: Center(
        child: PhotoHero(
          photo: 'images/flippers-alpha.png',
          width: 300.0,
          onTap: () {
            Navigator.of(context).push(MaterialPageRoute<void>(
              builder: (BuildContext context) {
                return Scaffold(
                  appBar: AppBar(
                    title: const Text('Flippers Page'),
                  ),
                  body: Container(
                    // The blue background emphasizes that it's a new route.
                    color: Colors.lightBlueAccent,
                    padding: const EdgeInsets.all(16),
                    alignment: Alignment.topLeft,
                    child: PhotoHero(
                      photo: 'images/flippers-alpha.png',
                      width: 100.0,
                      onTap: () {
                        Navigator.of(context).pop();
                      },
                    ),
                  ),
                );
              }
            ));
          },
        ),
      ),
    );
  }
}

重要な情報:

  • ユーザーがタップすると、InkWellソースヒーローを含む、 コードは次を使用して宛先ルートを作成します。MaterialPageRoute。 宛先ルートをプッシュするNavigatorのスタックトリガー アニメーション。
  • Containerを配置しますPhotoHero目的地で ルートの左上隅、AppBar
  • onTap()目的地までの方法PhotoHeroポップするNavigatorのスタック、アニメーションのトリガー それは飛ぶHero元のルートに戻ります。
  • 使用timeDilation遷移を遅くするプロパティ デバッグ中。

ラジアルヒーローアニメーション

ヒーローを変身させながらあるルートから別のルートへ飛行させる 円形から長方形への変換は滑らかです ヒーロー ウィジェットを使用して実装できる効果。 これを実現するために、コードは次の交差部分をアニメーション化します。 2 つのクリップ形状: 円と四角。 アニメーション全体を通して、サークル クリップ (および画像) からのスケールminRadiusmaxRadius、一方、正方形 クリップは一定のサイズを維持します。同時に、 画像はソース ルート内の位置からその位置に移動します。 目的地ルート上の位置。視覚的な例については この移行については、を参照してください。放射状変換マテリアルモーションスペックにある。

このアニメーションは複雑に見えるかもしれません (そして実際そうです)。をカスタマイズする ニーズに合わせた例を提供しました。面倒な作業はすべてあなたのために行われます。

どうしたの?

次の図は、先頭の切り取られた画像を示しています (t = 0.0)、最後 (a2aefffc-b480-47b3-b5ac-17daef0ebde2)アニメーションの。

Radial transformation from beginning to end

青のグラデーション (画像を表す) は、クリップの位置を示します。 図形が交差します。移行の初めに、 交差の結果は円形のクリップになります (ClipOval)。 変身中は、ClipOvalからのスケールminRadiusmaxRadius一方クリップ長方形一定のサイズを維持します。 トランジションの終わりに、円形と 長方形のクリップは、ヒーローと同じサイズの長方形を生成します。 ウィジェット。言い換えれば、トランジションの終わりには、画像は存在しません。 長めに切り取られています。

新しい Flutter サンプルを作成すると からのファイルを使用して更新します。ラジアル_ヒーロー_アニメーションGitHub ディレクトリ。

例を実行するには:

  • 3 つの円形のサムネイルのいずれかをタップして画像をアニメーション化します 新しいルートの途中にある大きな広場へ。 本来のルートを曖昧にしてしまいます。
  • 画像をタップするか、 を使用して前のルートに戻ります。 デバイスの前のルートに戻るジェスチャ。
  • を使用すると、移行をさらに遅くすることができます。timeDilation財産。

写真クラス

Photoクラスは、画像を保持するウィジェット ツリーを構築します。

class Photo extends StatelessWidget {
  Photo({ Key key, this.photo, this.color, this.onTap }) : super(key: key);

  final String photo;
  final Color color;
  final VoidCallback onTap;

  Widget build(BuildContext context) {
    return Material(
      // Slightly opaque color appears where the image has transparency.
      color: Theme.of(context).primaryColor.withOpacity(0.25),
      child: InkWell(
        onTap: onTap,
        child: Image.asset(
            photo,
            fit: BoxFit.contain,
          )
      ),
    );
  }
}

重要な情報:

  • Inkwellタップジェスチャをキャプチャします。 呼び出し関数は、onTap()に機能するPhotoのコンストラクター。
  • 飛行中、InkWell最初の水しぶきを引く 物質的な祖先。
  • マテリアル ウィジェットはわずかに不透明な色をしているため、 画像の透明な部分は色付きでレンダリングされます。 これにより、円から四角への移行が見やすくなります。 透明度のある画像でも。
  • Photoクラスには含まれていませんHeroウィジェットツリー内で。 アニメーションが機能するためには、ヒーローが を包みますRadialExpansionウィジェット。

RadialExpansion クラス

RadialExpansionデモの中核となるウィジェットは、 トランジション中に画像をクリップするウィジェット ツリー。 切り取られた形状は、円形のクリップの交差から生じます。 (飛行中に成長します)、 長方形のクリップを使用します (全体的に一定のサイズのままです)。

これを行うために、次のウィジェット ツリーを構築します。

RadialExpansion widget tree

コードは次のとおりです。

class RadialExpansion extends StatelessWidget {
  RadialExpansion({
    Key key,
    this.maxRadius,
    this.child,
  }) : clipRectSize = 2.0 * (maxRadius / math.sqrt2),
       super(key: key);

  final double maxRadius;
  final clipRectSize;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return ClipOval(
      child: Center(
        child: SizedBox(
          width: clipRectSize,
          height: clipRectSize,
          child: ClipRect(
            child: child,  // Photo
          ),
        ),
      ),
    );
  }
}

重要な情報:

  • 主人公が包みますRadialExpansionウィジェット。
  • 主人公が飛ぶと大きさが変わり、 それは子供のサイズを制限するため、 のRadialExpansionウィジェットはそれに合わせてサイズを変更します。
  • RadialExpansionアニメーションは 2 つのクリップを重ね合わせて作成されます。
  • この例では、次を使用してトゥイーン補間を定義します。MaterialRectCenterArcTween。 ヒーローアニメーションのデフォルトの飛行経路 ヒーローの角を使用してトゥイーンを補間します。 このアプローチは、ヒーローのアスペクト比に影響を与えます。 半径方向の変換なので、新しい飛行経路では次のようになります。MaterialRectCenterArcTweenを使用してトゥイーンを補間するには、 各ヒーローの中心点。

    コードは次のとおりです。

    static RectTween _createRectTween(Rect begin, Rect end) {
      return MaterialRectCenterArcTween(begin: begin, end: end);
    }

    主人公の飛行経路は依然として円弧を描きますが、 ただし、画像のアスペクト比は一定のままです。